package curves.math;

import java.util.ArrayList;
import java.util.List;
import curves.Point;

public class C2SplineCurveAlgorithm extends DeCasteljanCurveAlgorithm {

    @Override
    public List<Point> calculatePoints(List<Point> initialPoints, boolean open, int steps, int start, int end) {
        ArrayList<Point> rpoints = new ArrayList<Point>();
        List<Point> points = new ArrayList<Point>();
        List<Point> controlPoints = new ArrayList<Point>();

        points.addAll(initialPoints);

        rpoints.clear();


        Point bP;
        if (open) {
            bP = points.get(0);
        } else {
            bP = points.get(0).part(points.get(points.size() - 1), 1.0 / 3.0).part(points.get(0).part(points.get(1), 1.0 / 3.0), 0.5);
        }

        rpoints.clear();

        for (int i = 0; i + 1 < points.size(); i++) {

            Point b0 = bP;
            Point b1 = points.get(i).part(points.get(i + 1), 1.0 / 3.0);
            Point b2 = points.get(i).part(points.get(i + 1), 2.0 / 3.0);
            Point pp;
            if (i + 2 < points.size()) {
                pp = points.get(i + 2);
            } else {
                if (!open) {
                    pp = points.get(0);
                } else {
                    pp = points.get(points.size() - 1);
                }
            }
            Point b3 = b2.part(points.get(i + 1).part(pp, 1.0 / 3.0), 0.5);

            bP = b3;

            controlPoints.add(b0);
            controlPoints.add(b1);
            controlPoints.add(b2);
            controlPoints.add(b3);


        }

        if (!open) {
            Point b1 = points.get(points.size() - 1).part(points.get(0), 1.0 / 3.0);
            Point b0 = points.get(points.size() - 2).part(points.get(points.size() - 1), 2.0 / 3.0).part(b1, 0.5);
            Point b2 = points.get(points.size() - 1).part(points.get(0), 2.0 / 3.0);
            Point b3 = points.get(0).part(points.get(points.size() - 1), 1.0 / 3.0).part(points.get(0).part(points.get(1), 1.0 / 3.0), 0.5);

            controlPoints.add(b0);
            controlPoints.add(b1);
            controlPoints.add(b2);
            controlPoints.add(b3);

        } else {
            controlPoints.remove(controlPoints.size() - 1);
            controlPoints.add(points.get(points.size() - 1));
        }

        List<Point> temp = new ArrayList<Point>();
        List<Point> ptemp = new ArrayList<Point>();


        rpoints.clear();

        rpoints.addAll(controlPoints);


        for (int k = 0; k < steps; k++) {
            points.clear();
            int a;
            int b;
            if (k == 0) {
                a = 0;
                b = 4;
            } else {
                a = 3;
                b = 3;
            }
            for (int i = 0; i + a < rpoints.size(); i += b) {
                temp.clear();
                temp.add(rpoints.get(i).weight());
                temp.add(rpoints.get(i + 1).weight());
                temp.add(rpoints.get(i + 2).weight());
                temp.add(rpoints.get(i + 3).weight());
                ptemp.clear();
                List<Point> rez = recurCastel(temp);
                for (Point pp : rez) {
                    ptemp.add(pp.unweight());
                }
                if (i != 0) {
                    ptemp.remove(0);
                }
                points.addAll(ptemp);
            }
            rpoints.clear();
            rpoints.addAll(points);
        }

        return rpoints;
    }


    @Override
    public String toString() {
        return "C2 Spline";
    }
}
